package com.project.web.admin.service.core.impl;

import com.project.mapper.core.AreaMapper;
import com.project.model.core.Area;
import com.project.web.admin.service.common.impl.BaseServiceImpl;
import com.project.web.admin.service.core.AreaService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

@Service("areaServiceImpl")
public class AreaServiceImpl extends BaseServiceImpl<Area, Long> implements AreaService {

    private static final long serialVersionUID = 1302564972801640590L;

    @Autowired
    private AreaMapper areaMapper;

    /**
     * 获取根节点
     *
     * @return
     */
    public List<Area> getRoots() {
        return areaMapper.getRoots();
    }

    /**
     * 根据父节点ID查询所以的子节点
     *
     * @param parentId
     * @return
     */
    @Override
    public List<Area> findChildrenRootNodes(Long parentId) {
        return areaMapper.findChildrenRootNodes(parentId);
    }

    /**
     * 获取所有的根节点
     *
     * @return
     */
    @Override
    public List<Area> findOnlyRoots() {
        return areaMapper.findOnlyRoots();
    }

    /**
     * 保存区域实体中动态生成的属性数据
     *
     * @param entity
     * @return
     */
    @Override
    public Area save(Area entity) {
        Area parent = areaMapper.getById(entity.getParentId());
        setValue(entity, parent);
        return super.save(entity);
    }

    @Override
    public void updateNodes(Area entity) {
        //查询当前节点的父节点,并设置当前节点的值
        Area currentParent = areaMapper.getById(entity.getParentId());
        setValue(entity, currentParent);

        //需要批量更新的Area集合
        List<Area> updateAreaList = new ArrayList<Area>();
        updateAreaList.add(entity);

        //当前Area下的所有子节点
        List<Area> childrenAreaList = areaMapper.findChildrenNodes("%" + Area.TREE_PATH_SEPARATOR + entity.getId() + Area.TREE_PATH_SEPARATOR + "%");

        //业务操作集合
        Map<Long, Area> modifyMap = new LinkedHashMap<Long, Area>();
        modifyMap.put(entity.getId(), entity);
        for (Area area : childrenAreaList) {
            modifyMap.put(area.getId(), area);
        }

        //更新业务操作集合
        Iterator iter = modifyMap.entrySet().iterator();
        while (iter.hasNext()) {
            Map.Entry entry = (Map.Entry) iter.next();
            Long id = (Long) entry.getKey();
            if (!id.equals(entity.getId())) {
                Area areaTemp = (Area) entry.getValue();
                Area paretArea = modifyMap.get(areaTemp.getParentId());
                setValue(areaTemp, paretArea);
                modifyMap.put(id, areaTemp);
                //放入批量更新操作list
                updateAreaList.add(areaTemp);
            }
        }

        //批量更新
        areaMapper.updateNodes(updateAreaList);
    }

    /**
     * 根据treepath模糊查询所有的子节点
     *
     * @param parentId
     * @return
     */
    public List<Area> findChildrenNodes(Long parentId) {
        return sort(areaMapper.findChildrenNodes(Area.TREE_PATH_SEPARATOR + parentId + Area.TREE_PATH_SEPARATOR), parentId);
    }

    /**
     * 设置值
     *
     * @param area
     * @param parent
     */
    private void setValue(Area area, Area parent) {
        if (area == null) {
            return;
        }
        if (parent != null) {
            area.setTreePath(parent.getTreePath() + parent.getId() + Area.TREE_PATH_SEPARATOR);
            area.setFullName(parent.getFullName() + area.getName() + Area.FULL_NAME_SEPARATOR);
        } else {
            area.setTreePath(Area.TREE_PATH_SEPARATOR);
            area.setFullName(area.getName() + Area.FULL_NAME_SEPARATOR);
        }
        area.setGrade(StringUtils.countMatches(area.getTreePath(), Area.TREE_PATH_SEPARATOR) - 1);
    }

    /**
     * 根据上下级关系递归调整list的数据位置
     *
     * @param list     原始list
     * @param parentId 父级id
     * @return
     */
    private List<Area> sort(List<Area> list, Long parentId) {
        List<Area> tempList = new ArrayList<Area>();
        for (Area area : list) {
            if ((parentId == null && area.getParentId() == null) || (area.getParentId() != null && area.getParentId().equals(parentId))) {
                tempList.add(area);
                tempList.addAll(sort(list, area.getId()));
            }
        }
        return tempList;
    }
}
